/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package simhya;
import simhya.dataprocessing.chart.PlotFileType;
import simhya.simengine.Simulator;
import simhya.simengine.stochastic.*;
import simhya.model.store.faststore.*;
import simhya.model.store.*;
import java.util.*;
import simhya.simengine.*;
import simhya.dataprocessing.*;
import simhya.simengine.stochastic.*;
import simhya.model.flat.*;
import simhya.model.transition.*;
import simhya.utils.*;
import cern.jet.random.engine.RandomEngine;
import simhya.model.flat.parser.StochParser;
import simhya.simengine.paramexplore.*;



import simhya.matheval.*;



/**
 *
 * @author Luca
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

//      testBatch();
//        test();
        simulateModel("SIR.txt",20,100,"output.txt");
//       testParser();

        
    }

private static void simulateModel(String modelfile, double finalTime, int runs, String outfile){
    int points = 500;
    FlatModel model = null;
    long time;

    StochParser parser = new StochParser();
    try {model = parser.parseFromFile(modelfile);}
    catch(Exception e) {e.printStackTrace();}
    Simulator sim;
    StochasticDataCollector dc = new StochasticDataCollector(model);
    dc.setPrintConditionByTime(points, finalTime);
    

    
//    sim = SimulatorFactory.newSimulator(SimType.SSA, model, dc);
   sim = SimulatorFactory.newSimulator(SimType.GB, model, dc);
//    sim = new GBSimulator(model,dc);

    sim.setFinalTime(finalTime);
    sim.initialize();

    time = System.nanoTime();
    for (int i=0;i<runs;i++) {
        System.out.print("*******RUN " + (i+1) +" ");

        dc.newTrajectory();
        System.out.print("*");
        sim.resetModel();
        System.out.print("*");
        sim.reinitialize();
        System.out.println("*");
        sim.run();
    
        System.out.println("Simulation time " + String.format(Locale.US, "%.4f", sim.getLastSimulationTimeInSecs()) + " seconds ");
        System.out.println("Steps of simulation: " + sim.getLastSimulationSteps());
        System.out.println("Stochastic steps: " + sim.getLastSimulationStochasticSteps());
        System.out.println("Instantaneous steps: " + sim.getLastSimulationInstantaneousSteps());
        System.out.println("Timed steps: " + sim.getLastSimulationTimedSteps());
        System.out.println("Delayed steps: " + sim.getLastSimulationDelayedSteps());
        System.out.println("Average time per step: " + String.format(Locale.US, "%.4f", sim.getLastSimulationTimeInMillisecs()/sim.getLastSimulationSteps()) + " milliseconds ");
        System.out.println();
    }
    time = System.nanoTime() - time;
    System.out.println("Total simulation time: " + String.format(Locale.US, "%.4f", (double)time/1000000000) + " seconds.");
    

//    time = System.nanoTime();
//    dc.saveAllTrajectoriesToCSV(outfile, true);
//    time = System.nanoTime() - time;
//    System.out.println("Time to save csv: " + String.format(Locale.US, "%.4f", (double)time/1000000000) + " seconds.");

//    time = System.nanoTime();
//    TrajectoryStatistics stat = dc.collectTrajectoryStatistics();
//    time = System.nanoTime() - time;
//    System.out.println("Time to collect statistics: " + String.format(Locale.US, "%.4f", (double)time/1000000000) + " seconds.");

//    stat.saveAsCSV(StatType.AVERAGE, "average.txt");
//    stat.saveAsCSV(StatType.CV, "cv.txt");
//    stat.saveFinalStateStatsAsCSV("finalState.txt");

    ArrayList<String> v =new ArrayList<String>();
    v.add("s"); v.add("i"); v.add("r");
//    dc.setVarsToBePrinted(v);
//    dc.plotSingleTrajectoryToScreen(0);
    
    time = System.nanoTime();
    dc.plotAllTrajectoriesToScreen();
    time = System.nanoTime() - time;
    System.out.println("Time to plot all trajectories to screen: " + String.format(Locale.US, "%.4f", (double)time/1000000000) + " seconds.");

    
    
    
//    dc.plotAllTrajectories("all.pdf", PlotTarget.PDF);
//    dc.plotSingleTrajectory(0, "single.png", PlotTarget.PNG);
//    dc.fullLatexDocument = true;
//    dc.plotSingleTrajectory(0, "single.tex", PlotTarget.TEX);
//    dc.phasePlanePlotToScreen("i", "r");
//    dc.phaseSpacePlotToScreen("s", "i", "r");
    
    
//    stat.setVarsToPlot(v);
//    stat.saveAsCSV(StatType.CV, "cv.txt");
//    stat.plotTrajectoryStatisticsToScreen(StatType.CV);
//    stat.plotTrajectoryStatistics(StatType.CV,"cv.pdf",PlotFileType.PDF);
    //stat.plotTrajectoryStatistics(StatType.AVERAGE,"average.jpg",PlotTarget.JPG);
    //stat.plotFinalDistribution("final.pdf",PlotTarget.PDF);
 
}


private static void testBatch() {
    int points = 100;
    FlatModel model = null;
    long time;

    StochParser parser = new StochParser();
    try {model = parser.parseFromFile("SIR.txt");}
    catch(Exception e) {e.printStackTrace();}
    StatisticsParamExplorator explorer = new StatisticsParamExplorator(model,SimType.SSA);
    explorer.addParameterToExplore("kr", 0.1, 2.0, 5, false);
//    double[] v = {1.0, 2.0, 10.0};
    double[] v = {1.0,  2.5,  5.0,  7.5,   10.0};
    explorer.addParameterToExplore("ki", v);
    explorer.doNotSaveTrajectories();
    explorer.setRunsPerConfiguration(100);
    explorer.saveTrajectoryData(20, points, false);

    StatisticsExploratorDataCollector coll = explorer.run();
//    coll.saveFinalStateStatisticAsCSV(StatType.AVERAGE, "batch_final_average.txt");
//    ArrayList<String> var = new ArrayList<String>(); var.add("r");
    ArrayList<String> par = new ArrayList<String>(); par.add("ki");
    ArrayList<Double> vv = new ArrayList<Double>(); vv.add(1.0); vv.add(10.0);
    ArrayList<ArrayList<Double>> vals = new ArrayList<ArrayList<Double>>(); vals.add(vv);
    coll.plotParamPhasePlaneStatisticsToScreen(StatType.AVERAGE, "r", "i", par, vals);
//    coll.plot1ParamFinalStateStatisticsToScreen(StatType.AVERAGE, "kr", var, par, vals);

//    coll.plot2ParamFinalStateStatisticsAsSurface(StatType.AVERAGE, "kr", "ki", "r", null, null);
//    coll.plot2ParamFinalStateStatisticsAsColorMap(StatType.AVERAGE, "kr", "ki", "r", null, null);

}

private static void test() {
    
    int reps = 10000000;

    String expression = "k*Y + X";

//    JEP jep = new JEP();
//    jep.addVariable("X", 4.0);
//    jep.addVariable("Y", 2.0);
//    jep.addConstant("k", 5.0);
//    Node jepNode = null;
//    try {jepNode = jep.parse(expression); } catch (Exception e) {e.printStackTrace();}

    Evaluator eval = new Evaluator();
    eval.addVariable("X", 4.0);
    eval.addVariable("Y", 2.0);
    eval.addConstant("k", 5.0);
    int id = -1;
    try {id = eval.parse(expression); } catch (Exception e) { e.printStackTrace();}
    Expression exp = eval.getExpression(id);
    
    double x;
    double[] V = new double[2];
    double[] P = new double[1];

    SymbolArray array = new SymbolArray();
    array.addSymbol("X", 6.0);
    array.addSymbol("Y", 1.0);

    int ec = eval.newEvaluationCode();
   
    long time = System.nanoTime();
    for (int i=0;i<reps;i++) {
       //try { x = (Double)jep.evaluate(jepNode); }  catch (Exception e) {e.printStackTrace();}
       x = exp.computeValue();
       //x = exp.computeValue(array);
       //x = exp.computeValue(ec);
       //x = exp.computeValue(array,ec);
       //x = P[0]*V[1] + V[0];
    }
    time = System.nanoTime() - time;
    double t = (double)time / 1000000;
    System.out.println("Total time: " + t + " milliseconds ");
    System.out.println("Time per step: " + t/reps + " milliseconds ");


}
    
private static void testParser() {
    Evaluator eval = new Evaluator();
    eval.addVariable("X", 2.0);
    eval.addVariable("Y", 6.5);
    eval.addConstant("k", 16.0);
    int id = -1;
    try {
        eval.parse("ciccio(X) := (X > 0)*k");
        //id = eval.parse("ciccio(Y)");
        id = eval.parse("sqrt(ciccio(Y))");
    } catch (Exception e) { e.printStackTrace();}
    Expression exp = eval.getExpression(id);
    System.out.println(exp);
    double x = exp.computeValue();
    System.out.println("Value is " + x);
}


}

class Wrapper {
    double [] v;
    int n;

    public Wrapper(int n) {
        this.n = n;
        v = new double[n];
    }


    public void set(int k, double x) {
//        if (k < 0 || k >= n)
//            throw new RuntimeException("Sticazzi");
        v[k] = x;
    }

    public double get(int k) {
//        if (k < 0 || k >= n)
//            throw new RuntimeException("Sticazzi");
        return v[k];
    }




}



class Plus {
    public double compute(double x1, double x2) {
        return x1 + x2;
    }
}

 class Times {
    public double compute(double x1, double x2) {
        return x1 + x2;
    }
}